#ifndef __PROTO_H
#define __PROTO_H

#include "../serialize/encode.h"
#include "../utils/alg.h"

namespace conn::proto {

constexpr uint8_t TYPE_ACK = 0;
constexpr uint8_t TYPE_PING = 1;
constexpr uint8_t TYPE_PONG = 2;
constexpr uint8_t TYPE_SIMPLE_REQ = 3;
constexpr uint8_t TYPE_SIMPLE_RES = 4;
constexpr uint8_t TYPE_SESSION = 5;
constexpr uint8_t TYPE_REQ = 6;
constexpr uint8_t TYPE_RES = 7;
constexpr uint8_t TYPE_NOTIFY = 8;
constexpr uint8_t TYPE_NOTIFY_ACK = 9;

constexpr uint16_t HEAD = 0xE11E;
constexpr uint8_t HEAD0 = 0xE1;
constexpr uint8_t HEAD1 = 0x1E;
constexpr uint8_t END = 0xEF;

constexpr uint8_t CMD_STATUS = 0x00;
constexpr uint8_t CMD_LOG = 0x01;
constexpr uint8_t CMD_OTA_START = 0x02;
constexpr uint8_t CMD_OTA_TRANSLATE = 0x03;
constexpr uint8_t CMD_OTA_COMPLETE = 0x04;
constexpr uint8_t CMD_GET_TASK_INFO = 0x05;
constexpr uint8_t CMD_DOOR_LOCK = 0x06;
constexpr uint8_t CMD_LED_CTRL = 0x07;
constexpr uint8_t CMD_MOTOR_CTRL = 0x08;
constexpr uint8_t CMD_MOTOR_RESET = 0x09;
constexpr uint8_t CMD_MOTOR_RESET_ROW = 0x0A;
constexpr uint8_t CMD_PICK = 0x0B;

template <typename... Ts>
inline uint8_t make(uint8_t *buf, uint8_t type, uint8_t seq, const Ts &...ts) {
    using namespace serialize;

    encode_int(buf, HEAD);
    // encode_int(buf + 2, len)
    uint8_t len = encode_all(buf + 3, type, seq, ts...);
    uint8_t sum = utils::alg::xor_sum(buf + 3, len);
    encode_int<uint8_t>(buf + 2, 5 + len);
    encode_int<uint8_t>(buf + 3 + len, sum);
    encode_int<uint8_t>(buf + 4 + len, END);
    return len + 5;
}

} // namespace conn::proto

#endif
